package org.finesys.common.core.util;

import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

import lombok.experimental.UtilityClass;

/**
 * 异步线程操作工具类
 */

@UtilityClass
public class AsyncUtil {

	public static CompletableFuture<Void> run(Runnable... runnables) {
		return CompletableFuture.allOf(completableFuture(true, runnables));
	}

	public static void paraller(Runnable... runnables) {
		run(runnables).join();
	}

	public static void parallel(Boolean ignoreException, Runnable... runs) {
		CompletableFuture.allOf(completableFuture(ignoreException, runs)).join();
	}

	public static Object[] paraller(Supplier<?>... suppliers) {
		return parallel(true, suppliers);
	}

	public static Object[] parallel(Boolean ignoreException, Supplier<?>... suppliers) {
		CompletableFuture<?>[] completableFutures = completableFuture(ignoreException, suppliers);
		CompletableFuture.allOf(completableFutures).join();
		Object[] objects = new Object[completableFutures.length];

		for (int i = 0; i < completableFutures.length; ++i) {
			try {
				objects[i] = completableFutures[i].get();
			}
			catch (Exception e) {
				if (!ignoreException) {
					throw new RuntimeException(e.getMessage());
				}
			}
		}

		return objects;
	}

	public static CompletableFuture<?>[] completableFuture(boolean ignoreException, Supplier<?>... suppliers) {
		CompletableFuture<?>[] completableFutures = new CompletableFuture[suppliers.length];
		for (int i = 0; i < suppliers.length; i++) {
			Supplier<?> supplier = suppliers[i];
			completableFutures[i] = CompletableFuture.supplyAsync(() -> {
				Object res;
				try {
					res = supplier.get();
				}
				catch (Exception e) {
					if (!ignoreException) {
						throw new RuntimeException(e);
					}
					res = null;
				}
				return res;
			});
		}
		return completableFutures;
	}

	public static CompletableFuture<?>[] completableFuture(boolean ignoreException, Runnable... runnables) {
		CompletableFuture<?>[] completableFutures = new CompletableFuture[runnables.length];
		for (int i = 0; i < runnables.length; i++) {
			Runnable runnable = runnables[i];
			completableFutures[i] = CompletableFuture.runAsync(() -> {
				try {
					runnable.run();
				}
				catch (Exception e) {
					if (!ignoreException) {
						throw new RuntimeException(e);
					}

				}
			});
		}
		return completableFutures;
	}

}
